package referenceimpl

import (
	"context"
	"fmt"

	"github.com/bytedance/sonic"
	"gitee.com/leonscript/sally/v2/domain/aggregate"
	"gitee.com/leonscript/sally/v2/domain/entity"
	"gitee.com/leonscript/sally/v2/infrastructure/persistent"
	"gitee.com/leonscript/sally/v2/infrastructure/utils"

	"gorm.io/gorm"
)

type ClerkReferenceImpl struct {
	db *gorm.DB
}

func NewClerkReferenceImpl(db *gorm.DB) aggregate.Reference {
	return &ClerkReferenceImpl{db: db}
}

func (c *ClerkReferenceImpl) QueryWorkflowTemplateByID(ctx context.Context, id string) (result entity.WorkflowTemplate, err error) {
	client := persistent.NewWorkflowTemplateClient(c.db)
	workflowTemplatePO, err := client.QueryWorkflowTemplateByID(ctx, id)
	if err != nil {
		return result, err
	}

	if err = utils.StructCopy(ctx, &result, &workflowTemplatePO); err != nil {
		return result, err
	}

	return result, err
}

// CreateWorkflowTemplateTX 创建工作流模板
func (c *ClerkReferenceImpl) CreateWorkflowTemplateTX(ctx context.Context, workflowTemplate entity.WorkflowTemplate, tx *gorm.DB) (err error) {
	// 实体转换为PO
	var workflowTemplatePO persistent.WorkflowTemplate
	if err = utils.StructCopy(ctx, &workflowTemplatePO, &workflowTemplate); err != nil {
		return err
	}

	// 持久化保存
	return tx.WithContext(ctx).Create(&workflowTemplatePO).Error
}
func (c *ClerkReferenceImpl) CreateWorkflowTX(ctx context.Context, workflow entity.Workflow, tx *gorm.DB) (err error) {
	// workflow实体转换为PO
	var workflowPO persistent.Workflow
	if err = utils.StructCopy(ctx, &workflowPO, &workflow); err != nil {
		return err
	}
	workflowPO.ConditionParamsRaw, err = workflow.ConditionParams.MarshalToString()
	if err != nil {
		return err
	}

	// 持久化保存
	client := persistent.NewWorkflowClient(c.db)
	if err = client.CreateTX(ctx, workflowPO, tx); err != nil {
		return err
	}

	return err
}

func (c *ClerkReferenceImpl) CreateNodeTX(ctx context.Context, node entity.Node, tx *gorm.DB) (err error) {
	var nodePO persistent.Node
	if err = utils.StructCopy(ctx, &nodePO, &node); err != nil {
		return err
	}

	client := persistent.NewNodeClient(c.db)
	if err = client.CreateTX(ctx, nodePO, tx); err != nil {
		return err
	}

	return err
}

// CreateNodeTemplateTX 创建节点模板
func (c *ClerkReferenceImpl) CreateNodeTemplateTX(ctx context.Context, nodeTemplate entity.NodeTemplate, tx *gorm.DB) (err error) {
	// 实体转换为PO
	var nodeTemplatePO persistent.NodeTemplate
	if err = utils.StructCopy(ctx, &nodeTemplatePO, &nodeTemplate); err != nil {
		return err
	}

	// 序列化条件
	conditionsBytes, err := sonic.Marshal(nodeTemplate.Conditions)
	if err != nil {
		return err
	}
	nodeTemplatePO.ConditionsRaw = string(conditionsBytes)

	// 设置BusinessParams
	nodeTemplatePO.BusinessParams = nodeTemplate.BusinessParams

	// 持久化保存
	return tx.WithContext(ctx).Create(&nodeTemplatePO).Error
}

// CreateNodeTemplateReviewersTX 批量创建节点模板审批者
func (c *ClerkReferenceImpl) CreateNodeTemplateReviewersTX(ctx context.Context, reviewers []entity.NodeTemplateReviewer, tx *gorm.DB) (err error) {
	if len(reviewers) == 0 {
		return nil
	}

	// 实体转换为PO
	reviewerPOs, err := utils.ArrayCopy(ctx, persistent.NodeTemplateReviewer{}, reviewers)
	if err != nil {
		return err
	}

	// 批量保存
	client := persistent.NewNodeTemplateReviewerClient(c.db)
	return client.BatchCreateTX(ctx, tx, reviewerPOs...)
}

func (c *ClerkReferenceImpl) CreateReviewerTasksTX(ctx context.Context, reviewerTasks []entity.NodeReviewerTask, tx *gorm.DB) (err error) {
	client := persistent.NewNodeReviewerTaskClient(c.db)
	taskPOs, err := utils.ArrayCopy(ctx, persistent.NodeReviewerTask{}, reviewerTasks)
	if err != nil {
		return err
	}

	// 创建
	return client.BatchCreateTX(ctx, tx, taskPOs...)
}

func (c *ClerkReferenceImpl) QueryReviewerTaskByID(ctx context.Context, id string) (result entity.NodeReviewerTask, err error) {
	client := persistent.NewNodeReviewerTaskClient(c.db)
	reviewerTaskPO, err := client.QueryReviewerTaskByID(ctx, id)
	if err != nil {
		return result, err
	}
	if err = utils.StructCopy(ctx, &result, &reviewerTaskPO); err != nil {
		return result, err
	}
	return result, err
}

func (c *ClerkReferenceImpl) QueryNodeReviewerTasksByNodeIDTX(ctx context.Context, nodeID string, tx *gorm.DB) (result []entity.NodeReviewerTask, err error) {
	client := persistent.NewNodeReviewerTaskClient(c.db)
	reviewerTaskPOs, err := client.QueryByNodeIDTX(ctx, nodeID, tx)
	if err != nil {
		return result, err
	}
	for _, po := range reviewerTaskPOs {
		var task entity.NodeReviewerTask
		if err = utils.StructCopy(ctx, &task, &po); err != nil {
			return result, err
		}
		result = append(result, task)
	}
	return result, err
}

func (c *ClerkReferenceImpl) QueryAndLockWorkflowByCondTX(ctx context.Context, cond aggregate.QueryWorkflowCond, tx *gorm.DB) (result entity.Workflow, err error) {
	client := persistent.NewWorkflowClient(c.db)
	// 查询workflow
	workflowPO, err := client.QueryWorkflowByCondTX(ctx, cond, tx)
	if err != nil {
		return result, err
	}

	// workflow上锁
	_, err = client.LockTX(ctx, workflowPO.ID, tx)
	if err != nil {
		return result, err
	}

	// PO转换为实体
	err = utils.StructCopy(ctx, &result, &workflowPO)
	if err != nil {
		return result, err
	}
	if err = result.ConditionParams.UnmarshalFromString(workflowPO.ConditionParamsRaw); err != nil {
		return result, err
	}

	return result, err
}

func (c *ClerkReferenceImpl) QueryNodeTemplateByID(ctx context.Context, id string) (result entity.NodeTemplate, err error) {
	client := persistent.NewNodeTemplateClient(c.db)
	nodeTemplatePO, err := client.QueryNodeTemplateByID(ctx, id)
	if err != nil {
		return result, err
	}

	// 转换为实体
	if err = utils.StructCopy(ctx, &result, &nodeTemplatePO); err != nil {
		return result, err
	}

	// 设置BusinessParams
	result.BusinessParams = nodeTemplatePO.BusinessParams

	return result, sonic.Unmarshal([]byte(nodeTemplatePO.ConditionsRaw), &result.Conditions)
}

func (c *ClerkReferenceImpl) UpdateWorkflow(ctx context.Context, workflow entity.Workflow) (err error) {
	client := persistent.NewWorkflowClient(c.db)
	var workflowPO persistent.Workflow
	if err = utils.StructCopy(ctx, &workflowPO, &workflow); err != nil {
		return err
	}

	return client.Update(ctx, workflowPO)
}
func (c *ClerkReferenceImpl) UpdateWorkflowTX(ctx context.Context, workflow entity.Workflow, tx *gorm.DB) (err error) {
	client := persistent.NewWorkflowClient(c.db)
	var workflowPO persistent.Workflow
	if err = utils.StructCopy(ctx, &workflowPO, &workflow); err != nil {
		return err
	}

	return client.UpdateTX(ctx, workflowPO, tx)
}

func (c *ClerkReferenceImpl) UpdateNodeTX(ctx context.Context, node entity.Node, tx *gorm.DB) (err error) {
	client := persistent.NewNodeClient(c.db)
	var nodePO persistent.Node
	if err = utils.StructCopy(ctx, &nodePO, &node); err != nil {
		return err
	}

	return client.UpdateTX(ctx, nodePO, tx)
}

func (c *ClerkReferenceImpl) QueryNodeTemplateReviewers(ctx context.Context, nodeTemplateID string) (result []entity.NodeTemplateReviewer, err error) {
	client := persistent.NewNodeTemplateReviewerClient(c.db)
	reviewers, err := client.QueryReviewersByNodeTemplateID(ctx, nodeTemplateID)
	if err != nil {
		return result, err
	}

	return utils.ArrayCopy(ctx, entity.NodeTemplateReviewer{}, reviewers)
}

func (c *ClerkReferenceImpl) QueryNodeByIDTX(ctx context.Context, id string, tx *gorm.DB) (result entity.Node, err error) {
	client := persistent.NewNodeClient(c.db)
	nodePO, err := client.QueryNodeByIDTX(ctx, id, tx)
	if err != nil {
		return result, err
	}

	err = utils.StructCopy(ctx, &result, &nodePO)
	return result, err
}

func (c *ClerkReferenceImpl) UpdateNodeReviewerTaskTX(ctx context.Context, nodeReviewerTask entity.NodeReviewerTask, tx *gorm.DB) (err error) {
	client := persistent.NewNodeReviewerTaskClient(c.db)
	var nodeReviewerTaskPO persistent.NodeReviewerTask
	if err = utils.StructCopy(ctx, &nodeReviewerTaskPO, &nodeReviewerTask); err != nil {
		return err
	}

	return client.UpdateTX(ctx, nodeReviewerTaskPO, tx)
}

func (c *ClerkReferenceImpl) UpdateNodeReviewerTaskByCondTX(ctx context.Context, cond, nodeReviewerTask entity.NodeReviewerTask, tx *gorm.DB) (err error) {
	client := persistent.NewNodeReviewerTaskClient(c.db)
	// 构建条件
	var condPO persistent.NodeReviewerTask
	if err = utils.StructCopy(ctx, &condPO, &cond); err != nil {
		return err
	}

	// 构建修改值
	var nodeReviewerTaskPO persistent.NodeReviewerTask
	if err = utils.StructCopy(ctx, &nodeReviewerTaskPO, &nodeReviewerTask); err != nil {
		return err
	}

	// 执行更新
	return client.UpdateByCondTX(ctx, condPO, nodeReviewerTaskPO, tx)
}

func (c *ClerkReferenceImpl) QueryActivatedWorkflows(ctx context.Context, req aggregate.GetWorkflowsRequest) (result []aggregate.ActivatedWorkflow, total int64, err error) {
	client := persistent.NewActivatedWorkflowClient(c.db)
	activatedWorkflowPOs, total, err := client.QueryActivatedWorkflows(ctx, req)
	if err != nil {
		return result, total, err
	}

	result, err = utils.ArrayCopy(ctx, aggregate.ActivatedWorkflow{}, activatedWorkflowPOs)
	if err != nil {
		return result, total, err
	}

	// 数据转换
	result, err = c.getActivatedWorkflows(activatedWorkflowPOs)

	return result, total, err
}

func (c *ClerkReferenceImpl) QueryWorkflowByID(ctx context.Context, id string) (result entity.Workflow, err error) {
	client := persistent.NewWorkflowClient(c.db)
	workflowPO, err := client.QueryWorkflowByID(id)
	if err != nil {
		return result, err
	}

	// PO转为实体
	if err = utils.StructCopy(ctx, &result, &workflowPO); err != nil {
		return result, err
	}
	if err = sonic.Unmarshal([]byte(workflowPO.ConditionParamsRaw), &result.ConditionParams); err != nil {
		return result, fmt.Errorf("unmarshal condition params failed: %v", err)
	}

	return result, err
}

func (c *ClerkReferenceImpl) QueryNodeReviewTasks(ctx context.Context, req aggregate.GetNodeReviewTasksRequest) (result []aggregate.NodeReviewTask, total int64, err error) {
	client := persistent.NewNodeReviewTaskClient(c.db)
	taskPOs, total, err := client.QueryNodeReviewTasks(ctx, req)
	if err != nil {
		return result, total, err
	}

	// 手动转换，处理Comment字段的特殊转换
	for _, taskPO := range taskPOs {
		var task aggregate.NodeReviewTask
		if err = utils.StructCopy(ctx, &task, &taskPO); err != nil {
			return result, total, err
		}
		// 特殊处理Comment字段：从JSON字符串转换为BusinessParams
		if taskPO.Comment != "" {
			task.Comment, err = aggregate.NewBusinessParams(taskPO.Comment)
			if err != nil {
				return result, total, err
			}
		} else {
			task.Comment = aggregate.BusinessParams{}
		}
		result = append(result, task)
	}
	return result, total, err
}

func (c *ClerkReferenceImpl) QueryNodeReviewTasksTX(ctx context.Context, req aggregate.GetNodeReviewTasksRequest, tx *gorm.DB) (result []aggregate.NodeReviewTask, err error) {
	client := persistent.NewNodeReviewTaskClient(c.db)
	taskPOs, err := client.QueryNodeReviewTasksTX(ctx, req, tx)
	if err != nil {
		return result, err
	}

	// 手动转换，处理Comment字段的特殊转换
	for _, taskPO := range taskPOs {
		var task aggregate.NodeReviewTask
		if err = utils.StructCopy(ctx, &task, &taskPO); err != nil {
			return result, err
		}
		// 特殊处理Comment字段：从JSON字符串转换为BusinessParams
		if taskPO.Comment != "" {
			task.Comment, err = aggregate.NewBusinessParams(taskPO.Comment)
			if err != nil {
				return result, err
			}
		} else {
			task.Comment = aggregate.BusinessParams{}
		}
		result = append(result, task)
	}
	return result, err
}

func (c *ClerkReferenceImpl) DeleteWorkflowByCondTX(ctx context.Context, id string, tx *gorm.DB) (err error) {
	return persistent.NewWorkflowClient(c.db).DeleteWorkflowByCondTX(ctx, id, tx)
}

func (c *ClerkReferenceImpl) DeleteNodeByCondTX(ctx context.Context, workflowID string, tx *gorm.DB) (err error) {
	return persistent.NewNodeClient(c.db).DeleteNodeByCondTX(ctx, workflowID, tx)
}

func (c *ClerkReferenceImpl) DeleteNodeReviewerTaskByCondTX(ctx context.Context, workflowID string, tx *gorm.DB) (err error) {
	// 查询workflow下的节点
	nodes, err := persistent.NewNodeClient(c.db).QueryNodesByCondTX(ctx, persistent.Node{WorkflowID: workflowID}, tx)
	if err != nil {
		return err
	}

	// 删除任务
	return c.deleteReviewerTaskByNodePOs(ctx, nodes, tx)
}

func (c *ClerkReferenceImpl) Begin() *gorm.DB {
	return c.db.Begin()
}

func (c *ClerkReferenceImpl) Commit(tx *gorm.DB) error {
	return tx.Commit().Error
}

func (c *ClerkReferenceImpl) Rollback(tx *gorm.DB) error {
	return tx.Rollback().Error
}

func (c *ClerkReferenceImpl) getActivatedWorkflows(activatedWorkflowPOs []persistent.ActivatedWorkflow) (result []aggregate.ActivatedWorkflow, err error) {
	for _, activatedWorkflowPO := range activatedWorkflowPOs {
		activatedWorkflow := aggregate.ActivatedWorkflow{
			CreatedAt:             activatedWorkflowPO.CreatedAt,
			CurrentNodeID:         activatedWorkflowPO.CurrentNodeID,
			CurrentNodeName:       activatedWorkflowPO.CurrentNodeName,
			CurrentNodeTemplateID: activatedWorkflowPO.CurrentNodeTemplateID,
			FormContent:           activatedWorkflowPO.FormContent,
			Conclusion:            activatedWorkflowPO.Conclusion,
			ID:                    activatedWorkflowPO.ID,
			Name:                  activatedWorkflowPO.Name,
			Status:                activatedWorkflowPO.Status,
			UpdatedAt:             activatedWorkflowPO.UpdatedAt,
		}
		activatedWorkflow.BusinessParams, err = aggregate.NewBusinessParams(activatedWorkflowPO.BusinessParams)
		if err != nil {
			return result, err
		}
		result = append(result, activatedWorkflow)
	}

	return result, nil
}

// QueryNodeTemplateReviewersByNodeTemplateIDs 根据节点模板ID列表批量查询所有审批人
func (c *ClerkReferenceImpl) QueryNodeTemplateReviewersByNodeTemplateIDs(ctx context.Context, nodeTemplateIDs []string) (result []entity.NodeTemplateReviewer, err error) {
	if len(nodeTemplateIDs) == 0 {
		return result, nil
	}

	client := persistent.NewNodeTemplateReviewerClient(c.db)
	reviewers, err := client.QueryReviewersByNodeTemplateIDs(ctx, nodeTemplateIDs)
	if err != nil {
		return nil, err
	}

	// 转换为entity
	for _, reviewer := range reviewers {
		entityReviewer := entity.NodeTemplateReviewer{
			ID:             reviewer.ID,
			Kind:           reviewer.Kind,
			NodeTemplateID: reviewer.NodeTemplateID,
			ReviewerNos:    reviewer.ReviewerNos,
			ReviewerIDs:    reviewer.ReviewerIDs,
		}
		result = append(result, entityReviewer)
	}

	return result, nil
}

func (c *ClerkReferenceImpl) deleteReviewerTaskByNodePOs(ctx context.Context, nodes []persistent.Node, tx *gorm.DB) (err error) {
	var nodeIDs []string
	for _, node := range nodes {
		nodeIDs = append(nodeIDs, node.ID)
	}

	return persistent.NewNodeReviewerTaskClient(c.db).DeleteNodeReviewerTaskByCondTX(ctx, nodeIDs, tx)
}

// QueryNodeReviewerTaskByIDTX 根据任务ID查询审批任务（事务版本）
func (c *ClerkReferenceImpl) QueryNodeReviewerTaskByIDTX(ctx context.Context, id string, tx *gorm.DB) (result entity.NodeReviewerTask, err error) {
	client := persistent.NewNodeReviewerTaskClient(c.db)
	reviewerTaskPO, err := client.QueryReviewerTaskByIDTX(ctx, id, tx)
	if err != nil {
		return result, err
	}
	if err = utils.StructCopy(ctx, &result, &reviewerTaskPO); err != nil {
		return result, err
	}
	return result, err
}

// QueryNodeTemplatesByWorkflowTemplateID 根据工作流模板ID查询所有节点模板
func (c *ClerkReferenceImpl) QueryNodeTemplatesByWorkflowTemplateID(ctx context.Context, workflowTemplateID string) (result []entity.NodeTemplate, err error) {
	client := persistent.NewNodeTemplateClient(c.db)
	nodeTemplatePOs, err := client.QueryNodeTemplatesByWorkflowTemplateID(ctx, workflowTemplateID)
	if err != nil {
		return result, err
	}

	for _, nodeTemplatePO := range nodeTemplatePOs {
		var nodeTemplate entity.NodeTemplate
		if err = utils.StructCopy(ctx, &nodeTemplate, &nodeTemplatePO); err != nil {
			return result, err
		}
		result = append(result, nodeTemplate)
	}

	return result, nil
}

// QueryNodesByWorkflowID 根据工作流ID查询所有节点
func (c *ClerkReferenceImpl) QueryNodesByWorkflowID(ctx context.Context, workflowID string) (result []entity.Node, err error) {
	client := persistent.NewNodeClient(c.db)
	nodes, err := client.QueryNodesByWorkflowID(ctx, workflowID)
	if err != nil {
		return nil, err
	}

	for _, node := range nodes {
		result = append(result, entity.Node{
			ID:             node.ID,
			Status:         node.Status,
			WorkflowID:     node.WorkflowID,
			NodeTemplateID: node.NodeTemplateID,
			CreatedAt:      node.CreatedAt,
			UpdatedAt:      node.UpdatedAt,
		})
	}

	return result, nil
}

// QueryNodeTemplateReviewersByNodeTemplateID 根据节点模板ID查询所有审批人
func (c *ClerkReferenceImpl) QueryNodeTemplateReviewersByNodeTemplateID(ctx context.Context, nodeTemplateID string) (result []entity.NodeTemplateReviewer, err error) {
	client := persistent.NewNodeTemplateReviewerClient(c.db)
	reviewers, err := client.QueryReviewersByNodeTemplateID(ctx, nodeTemplateID)
	if err != nil {
		return nil, err
	}

	// 转换为entity
	for _, reviewer := range reviewers {
		entityReviewer := entity.NodeTemplateReviewer{
			ID:             reviewer.ID,
			Kind:           reviewer.Kind,
			NodeTemplateID: reviewer.NodeTemplateID,
			ReviewerNos:    reviewer.ReviewerNos,
			ReviewerIDs:    reviewer.ReviewerIDs,
		}
		result = append(result, entityReviewer)
	}

	return result, nil
}
